%%% File    : queue_server.erl
%%% Author  :  <>
%%% Description : 
%%% Created : 29 Mar 2011 by  <>

-module(queue_server).

-behaviour(gen_server).

-export([start/3]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
	terminate/2, code_change/3]).


%-record(queue, {id,
%	       msg_queue}).
-include("whh.hrl").

-define(SERVER, ?MODULE).

-record(state, {sup,
		idlist,
		queue}).  %%[{id, qid}]


%%-------
start(Sup, Nodes, Idlist) ->
    gen_server:start({local, ?SERVER}, ?MODULE, [Sup, Nodes, Idlist], []).

%%--------
init([Sup, Nodes, Idlist]) ->
    process_flag(trap_exit, true),
    ok = init_queue_db(Nodes -- [node()]),
    Queue = init_queue(Idlist),
    {ok, #state{sup=Sup,
		idlist=Idlist,
	       queue=Queue}}.

handle_call(_Req, _From, S) ->
    {reply, ok, S}.
  
handle_cast(redirect, S) ->
    redirect(S);

handle_cast(_Msg, S) ->
    {noreply, S}.

handle_info({'EXIT', _, normal}, S) ->
    {noreply, S};

handle_info({'EXIT', Pid, shutdown}, S=#state{sup=Sup}) ->
    case Pid =:= Sup of
	true ->
	    exit(shutdown);
	false ->
	    {noreply, S}
    end;

handle_info({'EXIT', Pid, _}, S=#state{sup=Sup}) ->
    case Pid of
	Sup ->
	    redirect(S);
	_Others ->
	    restart(Pid, S)
    end;

handle_info(_Info, S) ->
    {noreply, S}.

terminate(_Reason, _S) ->
    ok.
code_change(_Oldvsn, S, _Extra) ->
    {ok, S}.

%%---------
init_queue_db([]) ->  %%the first queue_server
    case mnesia:create_schema([node()]) of
	ok ->
	    ok;
	{error, _Reason} ->
	    mnesia:stop(),
	    mnesia:delete_schema([node()]),
	    mnesia:create_schema([node()])
    end,
    mnesia:start(),
    mnesia:create_table(myqueue, [{type, set}, {disc_copies, [node()]},{attributes, record_info(fields, myqueue)}]),
    ok;
init_queue_db(Nodes) ->
    mnesia:stop(),
    mnesia:delete_schema([node()]),
    mnesia:start(),
    mnesia:change_config(extra_db_nodes, Nodes),
    mnesia:wait_for_tables([queue], 30000),
    mnesia:change_table_copy_type(schema, node(), disc_copies),
    mnesia:add_table_copy(queue, node(), disc_copies),
    ok.

%%------
redirect(S=#state{idlist=Idlist}) ->
    case global:whereis_name(queue_sup) of
	Pid when is_pid(Pid) ->
	    link(Pid),
	    gen_server:cast(Pid, {redirect, node(), self(), Idlist}),
	    {noreply, S#state{sup=Pid}};
	undefined ->
	    gen_server:cast(self(), redirect),
	    {noreply, S#state{sup=undefined}}
    end.

restart(Pid, S=#state{queue=Q}) ->
    case lists:keysearch(Pid, 2, Q) of
	false ->
	    {noreply, S};
	{value, {Id, Pid}} ->
	    Npid = queue:start_link(Id),
	    {noreply, S#state{queue=[{Id, Npid}|lists:keydelete(Pid,2, Q)]}}
     end.

init_queue(Idlist) ->
    init_queue(Idlist, []).

init_queue([], Q) ->
    Q;
init_queue([Id|List], Queue) ->
    Qid = myqueue:start_link(Id),
    init_queue(List, [{Id, Qid}|Queue]).
